/**
 * conventional-changelog -n cc-config.mjs
 *
 * pkg.scripts is
 * "@changelog-with-config-angular": "conventional-changelog -p angular -n cc-config.mjs -i CHANGELOG.md -s -r 0"
 *
 * -p, --preset Name of the preset you want to use. Must be one of the following:
 *              angular, atom, codemirror, conventionalcommits, ember, eslint, express, jquery or jshint
 */
import compareFunc from "compare-func"

/**
 * scripts:{
 *   "changelog": "conventional-changelog -p angular -n cc-config.mjs -i CHANGELOG.md -s",
 *   "changelog-overwrite": "conventional-changelog -p angular -n cc-config.mjs -i CHANGELOG.md -s -r 0"
 *   "@changelog-with-config": "conventional-changelog -p angular -n cc-config.mjs -i CHANGELOG.md -s -r 0"
 * }
 *
 * build:       编译相关的修改，例如发布版本、对项目构建或者依赖的改动 (Build System)
 * chore        杂项变动，不改变源代码和测试用例 (Miscellaneous Chores)
 * ci:          持续集成修改 (Continuous Integration)
 * docs：       文档 (Documentations)
 * feat:        新功能 (Features)
 * fix:         修补某功能的 (Bug Fixes)
 * perf:        性能提升等优化相关 (Performance Improvements)
 * refactor：   代码重构 (Code Refactoring)
 * revert       回滚到上一个版本 (Reverts)
 * style：      代码样式修改, 注意不是 css 修改
 * test         测试用例修改 (Tests)
 */
/**
 * 默认 commit 类型
 *
 * 🏆 🏅 🥇 🥈 🥉
 * 💫 ⭐️ 🌟 ✨ ⚡️
 *
 * build    ♻️
 * chore    🎡
 * ci       📀
 * docs     📚
 * feat     💫
 * fix:     🪲
 * perf:    ✨
 * refactor 📦
 * revert   🔙
 * style    💎
 * test     🧩
 */
const DEFAULT_COMMIT_TYPES = Object.freeze(
    [
        { sort: "01", emoji: "♻️", type: "build", section: "Build System" },
        { sort: "01", emoji: "🎡", type: "chore", section: "Miscellaneous Chores" },
        { sort: "01", emoji: "📀", type: "ci", section: "Continuous Integration" },
        { sort: "01", emoji: "📚", type: "docs", section: "The Documentation" },
        { sort: "01", emoji: "💫", type: "feat", section: "Features" },
        { sort: "01", emoji: "🪲", type: "fix", section: "Bug Fixes" },
        { sort: "01", emoji: "✨", type: "perf", section: "Performance Improvements" },
        { sort: "01", emoji: "📦", type: "refactor", section: "Code Refactoring" },
        { sort: "01", emoji: "🔙", type: "revert", section: "Reverts" },
        { sort: "01", emoji: "💎", type: "style", section: "Styles" },
        { sort: "01", emoji: "🧩", type: "test", section: "Tests" },
        { sort: "99", emoji: "🚀", type: "BREAKING CHANGE", section: "BREAKING CHANGEs" },
    ].map(Object.freeze)
)

//

/**
 * Importent. don't delete - shenyc
 *
 * @param {string} type
 * @returns
 */
function getShowOptions(type) {
    let show = false
    let section = ""
    let emoji = ""
    let sort = ""
    const index = DEFAULT_COMMIT_TYPES.findIndex((v) => v.type == type)
    if (index >= 0) {
        const obj = DEFAULT_COMMIT_TYPES.at(index)
        const is_undefined = obj["hidden"] == undefined
        const not_hidden = !obj["hidden"]
        show = is_undefined || not_hidden
        section = obj["section"]
        emoji = obj["emoji"]
        sort = obj["sort"]
    }

    const getSection = () => {
        const result = `${section} ${emoji} `
        return result
    }

    return {
        show,
        section,
        emoji,
        sort,
        getSection,
    }
}

const writerOpts_angular = {
    writerOpts: {
        transform: (commit, context) => {
            let discard = true
            let type = commit.type ? commit.type.toLowerCase() : ""
            const xyz = getShowOptions(type)

            const notes = commit.notes.map((note) => {
                discard = false
                // console.log(note)
                // {
                //     "title" 'BREAKING CHANGE',
                //     "text": '脚注中除了, 其它条目应该采用类似 git trailer format 这样的惯例。'
                // }
                return {
                    ...note,
                    title: "BREAKING CHANGES 🚀🚀🚀", // BREAKING CHANGE Group
                }
            })

            discard = true
            const section = () => xyz.getSection()
            if (type === "feat") {
                type = section()
            } else if (type === "fix") {
                type = section()
            } else if (type === "docs") {
                type = section()
            } else if (type === "perf") {
                type = section()
            } else if (type === "refactor") {
                type = section()
            } else if (type === "test") {
                type = section()
            } else if (discard) {
                return // ---------------------------------
            } else if (type === "build") {
                type = section()
            } else if (type === "style") {
                type = section()
            } else if (type === "revert" || commit.revert) {
                type = section()
            } else if (type === "ci") {
                type = section()
            } else if (type === "chore") {
                type = section()
            } else if (discard) {
                return // ---------------------------------
            }

            // <type>[optional scope]: <description>
            const scope = commit.scope === "*" ? "" : commit.scope
            const shortHash = typeof commit.hash === "string" ? commit.hash.substring(0, 7) : commit.shortHash

            const issues = []
            let subject = commit.subject

            if (typeof subject === "string") {
                let url = context.repository
                    ? `${context.host}/${context.owner}/${context.repository}`
                    : context.repoUrl
                if (url) {
                    url = `${url}/issues/`
                    // Issue URLs.
                    subject = subject.replace(/#([0-9]+)/g, (_, issue) => {
                        issues.push(issue)
                        return `[#${issue}](${url}${issue})`
                    })
                }
                if (context.host) {
                    // User URLs.
                    subject = subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, username) => {
                        if (username.includes("/")) {
                            return `@${username}`
                        }

                        return `[@${username}](${context.host}/${username})`
                    })
                }
            }

            // remove references that already appear in the subject
            const references = commit.references.filter((reference) => !issues.includes(reference.issue))

            return {
                notes,
                type,
                scope,
                shortHash,
                subject,
                references,
            }
        },
        groupBy: "type",
        commitGroupsSort: "title",
        commitsSort: ["scope", "subject"], // commit sort
        noteGroupsSort: "title", // BREAKING CHANGE Group
        notesSort: compareFunc,
    },
}

/**
 * ?
 */
const writerOpts_atom = {
    writerOpts: {
        transform: (commit) => {
            if (!commit.emoji || typeof commit.emoji !== "string") {
                return
            }

            const emoji = commit.emoji.substring(0, 72)
            const emojiLength = emoji.length
            const shortHash = typeof commit.hash === "string" ? commit.hash.substring(0, 7) : commit.shortHash
            const shortDesc =
                typeof commit.shortDesc === "string" ? commit.shortDesc.substring(0, 72 - emojiLength) : undefined

            return {
                emoji,
                shortHash,
                shortDesc,
            }
        },
        groupBy: "emoji",
        commitGroupsSort: "title",
        commitsSort: ["emoji", "shortDesc"],
    },
}

/**
 * ?
 */
const writerOpts_codemirror = {
    writerOpts: {
        transform: (commit) => {
            if (!commit.language) {
                return
            }

            const shortHash = typeof commit.hash === "string" ? commit.hash.substring(0, 7) : commit.shortHash

            return {
                shortHash,
            }
        },
        groupBy: "language",
        commitGroupsSort: "title",
        commitsSort: ["language", "type", "message"],
    },
}

/**
 * ?
 */
const writerOpts_ember = {
    writerOpts: {
        transform: (commit) => {
            if (!commit.pr) {
                return
            }

            let tag = commit.tag

            if (commit.tag === "BUGFIX") {
                tag = "Bug Fixes"
            } else if (commit.tag === "CLEANUP") {
                tag = "Cleanup"
            } else if (commit.tag === "FEATURE") {
                tag = "Features"
            } else if (commit.tag === "DOC") {
                tag = "Documentation"
            } else if (commit.tag === "SECURITY") {
                tag = "Security"
            } else {
                return
            }

            const shortHash = typeof commit.hash === "string" ? commit.hash.substring(0, 7) : commit.shortHash

            return {
                tag,
                shortHash,
            }
        },
        groupBy: "tag",
        commitGroupsSort: "title",
        commitsSort: ["tag", "taggedAs", "message"],
    },
}

/**
 * 顺序输出
 */
const writerOpts_eslint = {
    writerOpts: {
        transform: (commit) => {
            let discard = true
            if (!commit.tag || typeof commit.tag !== "string") {
                return
            }

            discard = true
            let type = commit.type

            if (commit.type === "feat") {
                type = "Features"
            } else if (commit.type === "fix") {
                type = "Bug Fixes"
            } else if (commit.type === "perf") {
                type = "Performance Improvements"
            } else if (commit.type === "revert" || commit.revert) {
                type = "Reverts"
            } else if (discard) {
                return
            } else if (commit.type === "docs") {
                type = "Documentation"
            } else if (commit.type === "style") {
                type = "Styles"
            } else if (commit.type === "refactor") {
                type = "Code Refactoring"
            } else if (commit.type === "test") {
                type = "Tests"
            } else if (commit.type === "build") {
                type = "Build System"
            } else if (commit.type === "ci") {
                type = "Continuous Integration"
            }

            const shortHash = commit.hash.substring(0, 7)

            return {
                type,
                shortHash,
            }
        },
        groupBy: "tag",
        commitGroupsSort: "title",
        commitsSort: ["tag", "message"],
    },
}

/**
 * ?
 */
const writerOpts_express = {
    writerOpts: {
        transform: (commit) => {
            let component = commit.component

            if (commit.component === "perf") {
                component = "Performance"
            } else if (commit.component === "deps") {
                component = "Dependencies"
            } else {
                return
            }

            return {
                component,
            }
        },
        groupBy: "component",
        commitGroupsSort: "title",
        commitsSort: ["component", "shortDesc"],
    },
}
/**
 * 有输出
 */
const writerOpts_jquery = {
    writerOpts: {
        transform: (commit) => {
            if (!commit.component || typeof commit.component !== "string") {
                return
            }

            const shortHash = typeof commit.hash === "string" ? commit.hash.substring(0, 7) : commit.shortHash
            const references = commit.references.map((reference) => {
                return {
                    ...reference,
                    originalIssueTracker:
                        reference.prefix === "#" ? "https://bugs.jquery.com/ticket/" : reference.originalIssueTracker,
                }
            })

            return {
                shortHash,
                references,
            }
        },
        groupBy: "component",
        commitGroupsSort: "title",
        commitsSort: ["component", "shortDesc"],
    },
}

/**
 * ?
 */
const writerOpts_jshint = {
    writerOpts: {
        transform: (commit) => {
            let type = commit.type ? commit.type.toUpperCase() : ""

            if (type === "FEAT") {
                type = "Features"
            } else if (type === "FIX") {
                type = "Bug Fixes"
            } else {
                return
            }

            const hash = typeof commit.hash === "string" ? commit.hash.substring(0, 7) : commit.hash
            const notes = commit.notes.map((note) => {
                return {
                    ...note,
                    title: note.title === "BREAKING CHANGE" ? "BREAKING CHANGES" : note.title,
                }
            })

            return {
                type,
                hash,
                notes,
            }
        },
        groupBy: "type",
        commitGroupsSort: "title",
        commitsSort: ["type", "shortDesc"],
        noteGroupsSort: "title",
        notesSort: compareFunc,
    },
}

/**
 * 输出: templatetemplatetemplatetemplatetemplatetemplatetemplatetemplateBug Fixestemplate
 */
const writerOpts_test = {
    writerOpts: {
        mainTemplate: "{{commitGroups.[0].commits.[0].type}}{{testContext}}template",
    },
}

export {
    DEFAULT_COMMIT_TYPES,
    writerOpts_test,
    writerOpts_angular,
    writerOpts_atom,
    writerOpts_codemirror,
    writerOpts_ember,
    writerOpts_eslint,
    writerOpts_express,
    writerOpts_jquery,
    writerOpts_jshint,
}

export default writerOpts_angular
